

#include "./BSP/ATK_MS53L0/atk_ms53l0_iic.h"
#include "./SYSTEM/delay/delay.h"

/**
 * @brief       IIC接口延时函数，用于控制IIC读写速度
 * @param       无
 * @retval      无
 */
static inline void atk_ms53l0_iic_delay(void)
{
    delay_us(2);
}

/**
 * @brief       发送IIC起始信号
 * @param       无
 * @retval      无
 * @note        起始信号：在SCL为高电平期间，SDA从高电平向低电平切换
 */
void atk_ms53l0_iic_start(void)
{
    ATK_MS53L0_IIC_SDA(1);
    ATK_MS53L0_IIC_SCL(1);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SDA(0);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SCL(0);
    atk_ms53l0_iic_delay();
}

/**
 * @brief       发送IIC停止信号
 * @param       无
 * @retval      无
 * @note        停止信号：在SCL为高电平期间，SDA从低电平向高电平切换
 */
void atk_ms53l0_iic_stop(void)
{
    ATK_MS53L0_IIC_SDA(0);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SCL(1);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SDA(1);
    atk_ms53l0_iic_delay();
}

/**
 * @brief       等待IIC应答信号
 * @param       无
 * @retval      0: 应答信号接收成功
 *              1: 应答信号接收失败
 * @note        包含超时检测机制，防止程序陷入死循环
 */
uint8_t atk_ms53l0_iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;
    
    ATK_MS53L0_IIC_SDA(1);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SCL(1);
    atk_ms53l0_iic_delay();
    
    /* 等待从机应答，SDA变为低电平表示应答 */
    while (ATK_MS53L0_IIC_READ_SDA())
    {
        waittime++;
        
        /* 超时处理：等待超过250个计数，判定为应答失败 */
        if (waittime > 250)
        {
            atk_ms53l0_iic_stop();
            rack = 1;
            break;
        }
    }
    
    ATK_MS53L0_IIC_SCL(0);
    atk_ms53l0_iic_delay();
    
    return rack;
}

/**
 * @brief       发送ACK应答信号
 * @param       无
 * @retval      无
 * @note        ACK信号：在第9个时钟脉冲期间，SDA保持低电平
 */
void atk_ms53l0_iic_ack(void)
{
    ATK_MS53L0_IIC_SDA(0);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SCL(1);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SCL(0);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SDA(1);
    atk_ms53l0_iic_delay();
}

/**
 * @brief       发送非ACK应答信号
 * @param       无
 * @retval      无
 * @note        NACK信号：在第9个时钟脉冲期间，SDA保持高电平
 */
void atk_ms53l0_iic_nack(void)
{
    ATK_MS53L0_IIC_SDA(1);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SCL(1);
    atk_ms53l0_iic_delay();
    ATK_MS53L0_IIC_SCL(0);
    atk_ms53l0_iic_delay();
}

/**
 * @brief       IIC发送一个字节
 * @param       dat: 要发送的数据
 * @retval      无
 * @note        数据发送格式：高位在前，低位在后
 */
void atk_ms53l0_iic_send_byte(uint8_t dat)
{
    uint8_t t;
    
    /* 按位发送数据，高位在前 */
    for (t=0; t<8; t++)
    {
        ATK_MS53L0_IIC_SDA((dat & 0x80) >> 7);
        atk_ms53l0_iic_delay();
        ATK_MS53L0_IIC_SCL(1);
        atk_ms53l0_iic_delay();
        ATK_MS53L0_IIC_SCL(0);
        dat <<= 1;
    }
    /* 释放SDA线，准备接收应答 */
    ATK_MS53L0_IIC_SDA(1);
}

/**
 * @brief       IIC读取一个字节
 * @param       ack: ack=1时发送ack; ack=0时发送nack
 * @retval      接收到的数据
 * @note        数据接收格式：高位在前，低位在后
 */
uint8_t atk_ms53l0_iic_read_byte(uint8_t ack)
{
    uint8_t i;
    uint8_t dat = 0;
    
    /* 按位接收数据，高位在前 */
    for (i = 0; i < 8; i++ )
    {
        dat <<= 1;
        ATK_MS53L0_IIC_SCL(1);
        atk_ms53l0_iic_delay();
        
        if (ATK_MS53L0_IIC_READ_SDA())
        {
            dat++;
        }
        
        ATK_MS53L0_IIC_SCL(0);
        atk_ms53l0_iic_delay();
    }
    
    /* 根据参数决定发送ACK或NACK */
    if (ack == 0)
    {
        atk_ms53l0_iic_nack();
    }
    else
    {
        atk_ms53l0_iic_ack();
    }

    return dat;
}

/**
 * @brief       初始化IIC接口
 * @param       无
 * @retval      无
 * @note        配置SCL引脚为推挽输出模式，SDA引脚为开漏输出模式
 */
void atk_ms53l0_iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    /* 使能SCL和SDA引脚GPIO时钟 */
    ATK_MS53L0_IIC_SCL_GPIO_CLK_ENABLE();
    ATK_MS53L0_IIC_SDA_GPIO_CLK_ENABLE();
    
    /* 初始化SCL引脚 */
    gpio_init_struct.Pin    = ATK_MS53L0_IIC_SCL_GPIO_PIN;  /* SCL引脚 */
    gpio_init_struct.Mode   = GPIO_MODE_OUTPUT_PP;          /* 推挽输出 */
    gpio_init_struct.Pull   = GPIO_PULLUP;                  /* 上拉 */
    gpio_init_struct.Speed  = GPIO_SPEED_FREQ_HIGH;         /* 高速 */
    HAL_GPIO_Init(ATK_MS53L0_IIC_SCL_GPIO_PORT, &gpio_init_struct);
    
    /* 初始化SDA引脚 */
    gpio_init_struct.Pin    = ATK_MS53L0_IIC_SDA_GPIO_PIN;  /* SDA引脚 */
    gpio_init_struct.Mode   = GPIO_MODE_OUTPUT_OD;          /* 开漏输出 */
    HAL_GPIO_Init(ATK_MS53L0_IIC_SDA_GPIO_PORT, &gpio_init_struct);
    
    /* 初始状态：发送停止信号，确保IIC总线空闲 */
    atk_ms53l0_iic_stop();
}
